using System;
using System.Collections.Generic;
using Taimila.Entify.Sqlite;

namespace Taimila.Entify.UnitTests
{
	/// <summary>
	/// Helper class to create PersistentEntityModels for unit tests.
	/// </summary>
	internal static class TestFactory
	{
		/// <summary>
		/// Create in-memory entity context with given test name. Name must be unique
		/// to get empty untouched context.
		/// </summary>
		/// <param name="testName">
		/// Name of the test that uses created entity context. <see cref="System.String"/>
		/// </param>
		/// <returns>
		/// In-memory entity context. <see cref="EntityContext"/>
		/// </returns>
		public static EntityContext CreateInMemoryEntityContext(string testName)
		{
			EntityContextSettings settings = new EntityContextSettings()
			{
				ContextName = testName,
				InMemory = true,
				EnforceValidationRules = false
			};
			
			return EntityContextFactory.GetContext(settings);
		}
		
		/// <summary>
		/// Create in-memory entity context with given test name. Name must be unique
		/// to get empty untouched context. This context enforces validation rules for entities.
		/// </summary>
		/// <param name="testName">
		/// Name of the test that uses created entity context. <see cref="System.String"/>
		/// </param>
		/// <returns>
		/// In-memory entity context with entity validation. <see cref="EntityContext"/>
		/// </returns>
		public static EntityContext CreateInMemoryEntityContextWithValidation(string testName)
		{
			EntityContextSettings settings = new EntityContextSettings()
			{
				ContextName = testName,
				InMemory = true,
				EnforceValidationRules = true
			};
			
			return EntityContextFactory.GetContext(settings);
		}
		
		/// <summary>
		/// Create unique TestModel objects.
		/// </summary>
		/// <param name="count">
		/// How many objects will be created. <see cref="System.Int32"/>
		/// </param>
		/// <returns>
		/// List of created TestModels. <see cref="List<TestModel>"/>
		/// </returns>
		public static ValidPersistentEntity[] CreateValidPersistentEntities(int count)
		{
			List<ValidPersistentEntity> list = new List<ValidPersistentEntity>();
			
			for (int i = 0; i < count; i++)
			{
				ValidPersistentEntity model = new ValidPersistentEntity()
				{
					Text = "Text value " + i + 1,
					Number = i + 1,
					LongNumber = i + 2L,
					DoubleNumber = 3.5,
					DecimalNumber = 2.1M * i,
					Timestamp = new DateTime(2009,12,20).AddDays(i),
					Boolean = true,
					ByteNumber = (byte) 10,
					Char = 'C',
					Float = 2.2F,
					SByte = (sbyte) -10,
					UInt = (uint) 128,
					ULong = 123456UL,
					UShort = (ushort) 12,
					Short = (short) -12,
					Enumeration = TestEnumeration.Some,
					SerializableObject = new SerializableType()
				};

				list.Add(model);
			}
			
			return list.ToArray();
		}
		
		/// <summary>
		/// Create unique TestModel objects. This factory method allows caller to
		/// define minimum entity id for created entities. This way called can create
		/// multiple entity sets where all entities are still unique.
		/// </summary>
		/// <param name="count">
		/// How many objects will be created. <see cref="System.Int32"/>
		/// </param>
		/// <param name="minimumId">
		/// Minimum entity id for created entities. <see cref="System.Int32"/>
		/// </param>
		/// <returns>
		/// List of created test entities. <see cref="ValidPersistentEntity[]"/>
		/// </returns>
		public static ValidPersistentEntity[] CreateValidPersistentEntities(int count, int minimumId)
		{
			List<ValidPersistentEntity> list = new List<ValidPersistentEntity>();
			
			for (int i = 0; i < count; i++)
			{
				ValidPersistentEntity model = new ValidPersistentEntity()
				{
					Text = "Text value " + i + 1,
					Number = i + 1,
					LongNumber = i + 2L,
					DoubleNumber = 3.5,
					DecimalNumber = 2.1M * i,
					Timestamp = new DateTime(2009,12,20).AddDays(i),
					Boolean = true,
					ByteNumber = (byte) 10,
					Char = 'C',
					Float = 2.2F,
					SByte = (sbyte) -10,
					UInt = (uint) 128,
					ULong = 123456UL,
					UShort = (ushort) 12,
					Short = (short) -12,
					Enumeration = TestEnumeration.Some,
					SerializableObject = new SerializableType()
				};

				list.Add(model);
			}
			
			return list.ToArray();
		}
		
		/// <summary>
		/// Creates one TestModel.
		/// </summary>
		/// <returns>
		/// Created TestModel. <see cref="TestModel"/>
		/// </returns>
		public static ValidPersistentEntity CreateValidPersistentEntity()
		{	
			ValidPersistentEntity model = new ValidPersistentEntity()
				{
					Text = "Text value",
					Number = 1,
					LongNumber = long.MaxValue / 1000L,
					DoubleNumber = 3.5,
					DecimalNumber = 24282.09816M,
					Timestamp = new DateTime(2009,12,20),
					Boolean = true,
					ByteNumber = (byte) 10,
					Char = 'C',
					Float = 2.2F,
					SByte = (sbyte) -10,
					UInt = (uint) 128,
					ULong = 123456UL,
					UShort = (ushort) 12,
					Short = (short) -12,
					Enumeration = TestEnumeration.Some,
					SerializableObject = new SerializableType()
				};
			
			return model;
		}
		
		/// <summary>
		/// Create valid test entity that has single self relation property.
		/// </summary>
		/// <returns>
		/// A <see cref="EntityWithSingleSelfRelation"/>
		/// </returns>
		public static EntityWithSingleSelfRelation CreateValidEntityWithSingleSelfRelation()
		{
			EntityWithSingleSelfRelation entity = new EntityWithSingleSelfRelation()
			{
				Text = "Test entity with single self relation proprety"
			};
			
			return entity;
		}
		
		/// <summary>
		/// Creates persistent properties without values for type TestModule.
		/// </summary>
		/// <returns>
		/// List of properties in TestModule <see cref="List<PersistentProperty>"/>
		/// </returns>
		public static List<SqlitePersistentProperty> CreatePersistentPropertiesForTestModule(bool setValues)
		{
			List<SqlitePersistentProperty> properties = new List<SqlitePersistentProperty>();
			
			if(setValues)
			{
				properties.Add(new SqlitePersistentProperty() {Name = "Number", Type = typeof(int), Value = 1, PersistentName="NumberProperty" });
				properties.Add(new SqlitePersistentProperty() {Name = "Text", Type = typeof(string), Value = "Text value", PersistentName="TextProperty" });
				properties.Add(new SqlitePersistentProperty() {Name = "LongNumber", Type = typeof(long), Value = long.MaxValue / 1000L, PersistentName="LongNumberProperty", IndexName="First Index" });
				properties.Add(new SqlitePersistentProperty() {Name = "DoubleNumber", Type = typeof(double), Value = 3.5, PersistentName="DoubleNumberProperty", IndexName="First Index" });
				properties.Add(new SqlitePersistentProperty() {Name = "DecimalNumber", Type = typeof(decimal), Value = 24282.09816M, PersistentName="DecimalNumberProperty", IndexName="Yet.Another.Index" });
				properties.Add(new SqlitePersistentProperty() {Name = "Timestamp", Type = typeof(DateTime), Value = new DateTime(2009,12,20), PersistentName="TimestampProperty" });
				properties.Add(new SqlitePersistentProperty() {Name = "ByteNumber", Type = typeof(byte), Value = (byte)10, PersistentName="ByteProperty" });
				properties.Add(new SqlitePersistentProperty() {Name = "Boolean", Type = typeof(bool), Value = true, PersistentName="BooleanProperty" });
				properties.Add(new SqlitePersistentProperty() {Name = "Char", Type = typeof(char), Value = 'C', PersistentName="CharProperty" });
				properties.Add(new SqlitePersistentProperty() {Name = "SByte", Type = typeof(sbyte), Value = (sbyte)-10, PersistentName="SByteProperty" });
				properties.Add(new SqlitePersistentProperty() {Name = "Short", Type = typeof(short), Value = (short) -12, PersistentName="ShortProperty" });
				properties.Add(new SqlitePersistentProperty() {Name = "Float", Type = typeof(float), Value = 2.2F, PersistentName="FloatProperty" });
				properties.Add(new SqlitePersistentProperty() {Name = "UInt", Type = typeof(uint), Value = (uint) 128, PersistentName="UintProperty" });
				properties.Add(new SqlitePersistentProperty() {Name = "ULong", Type = typeof(ulong), Value = 123456UL, PersistentName="UlongProperty" });
				properties.Add(new SqlitePersistentProperty() {Name = "UShort", Type = typeof(ushort), Value = (ushort) 12, PersistentName="UshortProperty" });
				properties.Add(new SqlitePersistentProperty() {Name = "Enumeration", Type = typeof(TestEnumeration), Value = TestEnumeration.Some, PersistentName="EnumProperty" });
				properties.Add(new SqlitePersistentProperty() {Name = "SerializableObject", Type = typeof(SerializableType), Value = new SerializableType(), PersistentName="SerializableProperty" });
			}
			else
			{
				properties.Add(new SqlitePersistentProperty() {Name = "Number", Type = typeof(int), Value = null, PersistentName="NumberProperty" });
				properties.Add(new SqlitePersistentProperty() {Name = "Text", Type = typeof(string), Value = null, PersistentName="TextProperty" });
				properties.Add(new SqlitePersistentProperty() {Name = "LongNumber", Type = typeof(long), Value = null, PersistentName="LongNumberProperty", IndexName="First Index" });
				properties.Add(new SqlitePersistentProperty() {Name = "DoubleNumber", Type = typeof(double), Value = null, PersistentName="DoubleNumberProperty", IndexName="First Index" });
				properties.Add(new SqlitePersistentProperty() {Name = "DecimalNumber", Type = typeof(decimal), Value = null, PersistentName="DecimalNumberProperty", IndexName="Yet.Another.Index" });
				properties.Add(new SqlitePersistentProperty() {Name = "Timestamp", Type = typeof(DateTime), Value = null, PersistentName="TimestampProperty" });
				properties.Add(new SqlitePersistentProperty() {Name = "ByteNumber", Type = typeof(byte), Value = null, PersistentName="ByteProperty" });
				properties.Add(new SqlitePersistentProperty() {Name = "Boolean", Type = typeof(bool), Value = null, PersistentName="BooleanProperty" });
				properties.Add(new SqlitePersistentProperty() {Name = "Char", Type = typeof(char), Value = null, PersistentName="CharProperty" });
				properties.Add(new SqlitePersistentProperty() {Name = "SByte", Type = typeof(sbyte), Value = null, PersistentName="SByteProperty" });
				properties.Add(new SqlitePersistentProperty() {Name = "Short", Type = typeof(short), Value = null, PersistentName="ShortProperty" });
				properties.Add(new SqlitePersistentProperty() {Name = "Float", Type = typeof(float), Value = null, PersistentName="FloatProperty" });
				properties.Add(new SqlitePersistentProperty() {Name = "UInt", Type = typeof(uint), Value = null, PersistentName="UintProperty" });
				properties.Add(new SqlitePersistentProperty() {Name = "ULong", Type = typeof(ulong), Value = null, PersistentName="UlongProperty" });
				properties.Add(new SqlitePersistentProperty() {Name = "UShort", Type = typeof(ushort), Value = null, PersistentName="UshortProperty" });
				properties.Add(new SqlitePersistentProperty() {Name = "Enumeration", Type = typeof(TestEnumeration), Value = null, PersistentName="EnumProperty" });
				properties.Add(new SqlitePersistentProperty() {Name = "SerializableObject", Type = typeof(SerializableType), Value = null, PersistentName="SerializableProperty" });
			}

			return properties;
		}
	}
}
